/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package net.easoftware.code.beans;

import com.excel2objects.common.excel.engine.ExcelParser;
import com.excel2objects.common.excel.exceptions.UnparsbleException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import net.easoftware.code.beans.cargas.threading.CargasFilteringThread;
import net.easoftware.code.beans.facade.LineaNegocio;
import net.easoftware.code.beans.facade.RangoEmpresaFc;
import net.easoftware.code.beans.facade.UnidadNegocio;
import net.easoftware.code.beans.jpa.Cargadatos;
import net.easoftware.code.util.Constantes;
import org.apache.log4j.Logger;

/**
 *
 * @author waumovil-eliu
 */
public class TipoCargaDatos implements Serializable, Runnable {

    private static final Logger log = Logger.getLogger(TipoCargaDatos.class.getName());
    private ExcelParser parser;
    private String descripcion;
    private List data = new LinkedList();
    private Class tipo;
    private List<CargasFilteringThread> filtros = new LinkedList<CargasFilteringThread>();
    private List<LineaNegocio> lineasNegocio;
    private List<UnidadNegocio> unidadesNegocio;
    private List<RangoEmpresaFc> rangosEmpresa;
    private Integer registrosEnviados = 0;
    private boolean preparingThreads = false;
    private InputStream memoryData;
    private String fileNameData;
    private Integer skipRows;
    private Cargadatos cargaExistente;
    private Map<String, List> dataMap = new LinkedHashMap<>();

    public Map<String, List> getDataMap() {
        return dataMap;
    }

    public void setDataMap(Map<String, List> dataMap) {
        this.dataMap = dataMap;
    }

    public Cargadatos getCargaExistente() {
        return cargaExistente;
    }

    public void setCargaExistente(Cargadatos cargaExistente) {
        this.cargaExistente = cargaExistente;
    }

    public String getFileNameData() {
        return fileNameData;
    }

    public void setFileNameData(String fileNameData) {
        this.fileNameData = fileNameData;
    }

    public boolean isPreparingThreads() {
        return preparingThreads;
    }

    public void setPreparingThreads(boolean preparingThreads) {
        this.preparingThreads = preparingThreads;
    }

    public Integer getRegistrosEnviados() {
        return registrosEnviados;
    }

    public void setRegistrosEnviados(Integer registrosEnviados) {
        this.registrosEnviados = registrosEnviados;
    }

    public List<RangoEmpresaFc> getRangosEmpresa() {
        return rangosEmpresa;
    }

    public void setRangosEmpresa(List<RangoEmpresaFc> rangosEmpresa) {
        this.rangosEmpresa = rangosEmpresa;
    }

    public TipoCargaDatos(ExcelParser parser, String descripcion, Class tipo) {
        this.parser = parser;
        this.descripcion = descripcion;
        this.tipo = tipo;
    }

    public Class getTipo() {
        return tipo;
    }

    public void setTipo(Class tipo) {
        this.tipo = tipo;
    }

    public List<LineaNegocio> getLineasNegocio() {
        return lineasNegocio;
    }

    public void setLineasNegocio(List<LineaNegocio> lineasNegocio) {
        this.lineasNegocio = lineasNegocio;
    }

    public List<UnidadNegocio> getUnidadesNegocio() {
        return unidadesNegocio;
    }

    public void setUnidadesNegocio(List<UnidadNegocio> unidadesNegocio) {
        this.unidadesNegocio = unidadesNegocio;
    }

    public List<CargasFilteringThread> getFiltros() {
        return filtros;
    }

    public void setFiltros(List<CargasFilteringThread> filtros) {
        this.filtros = filtros;
    }

    public List getData() {
        return data;
    }

    public void setData(List data) {
        this.data = data;
    }

    public String getDescripcion() {
        return descripcion;
    }

    public void setDescripcion(String descripcion) {
        this.descripcion = descripcion;
    }

    public InputStream getMemoryData() {
        return memoryData;
    }

    public void setMemoryData(InputStream memoryData) {
        this.memoryData = memoryData;
    }

    public Integer getSkipRows() {
        return skipRows;
    }

    public void setSkipRows(Integer skipRows) {
        this.skipRows = skipRows;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 97 * hash + ( this.descripcion != null ? this.descripcion.hashCode() : 0 );
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final TipoCargaDatos other = (TipoCargaDatos) obj;
        if (( this.descripcion == null ) ? ( other.descripcion != null ) : !this.descripcion.equals(other.descripcion)) {
            return false;
        }
        return true;
    }

    private int calculateThreads(int dataSize) {
        int totalThreads = dataSize > Constantes.LOAD_SIZE_ON_FILTERING
                ? ( dataSize / Constantes.LOAD_SIZE_ON_FILTERING ) : 1;
        double exceed = (double) ( totalThreads * Constantes.LOAD_SIZE_ON_FILTERING ) / (double) dataSize;
        if (exceed > 0) {
            totalThreads += (int) Math.ceil(exceed);
        }
        return totalThreads;
    }

    @Override
    public void run() {
        try {
            this.preparingThreads = true;
            this.data = parser.getObjects(new FileInputStream(new File(this.fileNameData)), this.tipo);
            this.registrosEnviados = this.data.size();

            /* if (memData != null && !memData.isEmpty()) {
             DataFilterConf dataFilterCfg = (DataFilterConf) this.tipo.getAnnotation(DataFilterConf.class);
             DataFilter dataFilter = (DataFilter) dataFilterCfg.filter().newInstance();
             int totalThreads = calculateThreads(memData.size());
             int initArrPos = 0;
             int endArrPos = ( Constantes.LOAD_SIZE_ON_FILTERING >= memData.size() ) ? ( memData.size() - 1 ) : Constantes.LOAD_SIZE_ON_FILTERING;
             for (int i = 0; i < totalThreads; i++) {
             Integer sigLote = Constantes.LOAD_SIZE_ON_FILTERING;
             if (initArrPos > memData.size()) {
             break;
             }
             if (endArrPos > memData.size()) { // si es mayor a lo real le quita la diferencia
             endArrPos -= ( endArrPos - memData.size() );
             sigLote = memData.size() - endArrPos;
             }
             endArrPos--;
             log.info("******* Preparando nuevo hilo ******");
             CargasFilteringThread ft = new CargasFilteringThread();
             try {
             ft.setData(new LinkedList(memData.subList(initArrPos, endArrPos)));
             log.info("entregando seccion: " + initArrPos + " hasta " + endArrPos);
             }
             catch (Exception e) {
             log.error("Error entregando seccion, nueva seccion:" + initArrPos + " hasta " + ( memData.size() - 1 ));
             ft.setData(new LinkedList(memData.subList(initArrPos, memData.size() - 1)));
             log.error(e);
             }
             ft.setFilter(dataFilter);
             ft.setLineasNegocio(lineasNegocio);
             ft.setUnidadesNegocio(unidadesNegocio);
             ft.setRangos(rangosEmpresa);
             ft.setParent(this);
             filtros.add(ft);
             String threadKey = "ProcThread-" + filtros.size();
             Thread t = new Thread(ft, threadKey);
             log.info("Lanzando hilo de procesamiento..." + t.getName() + " carga: " + ft.getData().size());
             log.info("****** hilo lanzado ******");
             t.start();


             initArrPos += ( endArrPos );
             endArrPos += sigLote;
             }
             preparingThreads = false;
             } else {
             log.error("No se puede cargar archivos vacios!");
             }*/
            preparingThreads = false;
        }
        catch (FileNotFoundException | ClassNotFoundException | IllegalAccessException | InvocationTargetException | NoSuchMethodException | InstantiationException | UnparsbleException ex) {
            log.error("error", ex);
        }
    }
}
